package yolo

import (
	"appengine/datastore"
	"html"
	"net/http"
	"html/template"
	"strings"
	"time"
)

type AdminPage struct {
	writer http.ResponseWriter
	XsrfToken string
}

func NewAdminPage(w http.ResponseWriter, r *http.Request) *AdminPage {
	page := new(AdminPage)
	page.writer = w
	return page
}

type PollContextPageData struct {
	Key string
	PollContext
}

// /admin -------------------------------------------------------------------
type AdminTopPage struct {
	*AdminPage
	PollContexts []*PollContextPageData
	SupportedSites []string
}

func NewAdminTopPage(w http.ResponseWriter, r *http.Request, keys []*datastore.Key, contexts []PollContext, sites []string) *AdminTopPage {
	data := make([]*PollContextPageData, 0, len(keys))
	for i, v := range contexts {
		data = append(data, &PollContextPageData{keys[i].Encode(), v})
	}
	return &AdminTopPage{NewAdminPage(w, r), data, sites}
}

func (page *AdminTopPage) Render() {
	if err := adminTemplate.Execute(page.writer, page); err != nil {
		http.Error(page.writer, err.Error(), http.StatusInternalServerError)
	}
}

// /admin/users -------------------------------------------------------------
type AdminUsersPage struct {
	*AdminPage
	Users []User
	From int
	To int
	Next int
}

func NewAdminUsersPage(w http.ResponseWriter, r *http.Request, u []User, offset, limit int) *AdminUsersPage {
	return &AdminUsersPage{NewAdminPage(w, r), u, offset, offset+limit, offset+limit+1}
}

func (page *AdminUsersPage) Render() {
	if err := adminUsersTemplate.Execute(page.writer, page); err != nil {
		http.Error(page.writer, err.Error(), http.StatusInternalServerError)
	}
}

// /admin/issues ------------------------------------------------------------
type AdminIssuesPage struct {
	*AdminPage
	Issues []Issue
	From int
	To int
	Next int
}

func NewAdminIssuesPage(w http.ResponseWriter, r *http.Request, i []Issue, offset, limit int) *AdminIssuesPage {
	return &AdminIssuesPage{NewAdminPage(w, r), i, offset, offset+limit, offset+limit+1}
}

func (page *AdminIssuesPage) Render() {
	if err := adminIssuesTemplate.Execute(page.writer, page); err != nil {
		http.Error(page.writer, err.Error(), http.StatusInternalServerError)
	}
}

// /admin/user --------------------------------------------------------------
type AdminUserPage struct {
	*AdminPage
	Email string
	Commits []*CountMap
	RelatedUsers []*CountMap
}

func NewAdminUserPage(w http.ResponseWriter, r *http.Request, email string, commits, users []*CountMap) *AdminUserPage {
	return &AdminUserPage{NewAdminPage(w, r), email, commits, users}
}

func (page *AdminUserPage) Render() {
	if err := adminUserTemplate.Execute(page.writer, page); err != nil {
		http.Error(page.writer, err.Error(), http.StatusInternalServerError)
	}
}

// /admin/activities --------------------------------------------------------
type AdminActivitiesPage struct {
	*AdminPage
	Activities []interface{}
	From int
	To int
	Next int
}

func NewAdminActivitiesPage(w http.ResponseWriter, r *http.Request, a []interface{}, offset, limit int) *AdminActivitiesPage {
	return &AdminActivitiesPage{NewAdminPage(w, r), a, offset, offset+limit, offset+limit+1}
}

func (page *AdminActivitiesPage) Render() {
	if err := adminActivitiesTemplate.Execute(page.writer, page); err != nil {
		http.Error(page.writer, err.Error(), http.StatusInternalServerError)
	}
}

// /admin/issue -------------------------------------------------------------
type AdminIssuePage struct {
	*AdminPage
	*IssueDetailData
}

func NewAdminIssuePage(w http.ResponseWriter, r *http.Request, detail *IssueDetailData) *AdminIssuePage {
	return &AdminIssuePage{NewAdminPage(w, r), detail}
}

func (page *AdminIssuePage) Render() {
	if err := adminIssueTemplate.Execute(page.writer, page); err != nil {
		http.Error(page.writer, err.Error(), http.StatusInternalServerError)
	}
}

var funcs = template.FuncMap{
	"date": dateFormatter,
	"lines": textHtmlFormatter,
}

const dateFormatLayout = "2006-01-02 15:04:05 MST"

func dateFormatter(t time.Time) string {
	return t.Format(dateFormatLayout)
}

func textHtmlFormatter(s string) template.HTML {
	lines := strings.Split(s, "\n")
	for i, line := range lines {
		lines[i] = html.EscapeString(line)
	}
	return template.HTML(strings.Join(lines, "<br />"))
}

var adminTemplate, e1 = template.New("admin.html").Funcs(funcs).ParseFiles("tmpl/admin.html")
var adminIssuesTemplate, e2 = template.New("admin_issues.html").Funcs(funcs).ParseFiles("tmpl/admin_issues.html")
var adminIssueTemplate, e3 = template.New("admin_issue.html").Funcs(funcs).ParseFiles("tmpl/admin_issue.html")
var adminUsersTemplate, e4 = template.New("admin_users.html").Funcs(funcs).ParseFiles("tmpl/admin_users.html")
var adminUserTemplate, e5 = template.New("admin_user.html").Funcs(funcs).ParseFiles("tmpl/admin_user.html")
var adminActivitiesTemplate, e6 = template.New("admin_activities.html").Funcs(funcs).ParseFiles("tmpl/admin_activities.html")
